package it.eng.area118.mdocommon.android.rest;

import it.eng.area118.mdocommon.ServiceEndPoint;
import it.eng.area118.mdocommon.ServiceInvoker;
import it.eng.area118.mdocommon.android.SharedPreferenceCallback;
import it.eng.area118.mdocommon.android.SharedPreferencesManager;
import it.eng.area118.mdocommon.android.log.BasicLogger;
import it.eng.area118.mdocommon.android.util.ConfigurationConstants;
import it.eng.area118.mdocommon.android.util.SharedPreferenceUtil;

import java.util.ArrayList;
import java.util.List;

import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import android.util.Log;

/**
 * 
 * @author Luigi Bifulco Rest Service Invoker Realization for invoke REST
 *         operations Use the RestServiceEndpoint with this invoke
 *         implementation For the supported methods type see the well-known
 *         HTTP/1.1 methods (GET, POST, etc).
 */
public class RestServiceInvoker implements ServiceInvoker {

	private final static String TAG = "RestServiceInvoker";

	private static RestServiceInvoker INSTANCE;
	protected RestTemplate template;

	private RestServiceInvoker() {

		this.template = new RestTemplate();
		final HttpComponentsClientHttpRequestFactory reqFactory = ((HttpComponentsClientHttpRequestFactory) this.template
				.getRequestFactory());

		// BasicLogger.writeLog(TAG, "HTTP Request Factory type is: " +
		// this.template.getRequestFactory());
		// BasicLogger.writeLog(TAG, "HTTP Client type is: " + reqFactory.getHttpClient());
		// BasicLogger.writeLog(TAG, "HTTP Connection Manager type is: " +
		// reqFactory.getHttpClient().getConnectionManager());

		int seconds = SharedPreferenceUtil.getSharedPrefsValue(
				ConfigurationConstants.conf_server_time_out_key, 30);
		int milliseconds = seconds * 1000;
		HttpParams params = reqFactory.getHttpClient().getParams();
		reqFactory.setReadTimeout(milliseconds);
		HttpConnectionParams.setConnectionTimeout(params, milliseconds);
		HttpConnectionParams.setSoTimeout(params, milliseconds);

		List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
		//Converter jsonConverter = new Converter();
		
		MappingJacksonHttpMessageConverter jsonConverter = new MappingJacksonHttpMessageConverter();

		converters.add(jsonConverter);
		this.template.setMessageConverters(converters);

		
		this.template.setErrorHandler(new AndroidResponseErrorHandler());

		// SharedPreferencesManager prefsManager = (SharedPreferencesManager)
		// AndroidApplicationContext.getInstance()
		// .getApplicationContextValue(ContextMapKeyEnum.CONFIGURATIONS_MANAGER.name());
		SharedPreferencesManager prefsManager = SharedPreferencesManager
				.getInstance();
		prefsManager
				.addSharedPreferencesListener(new SharedPreferenceCallback() {

					@Override
					public void onPreferenceChanged(String key, Object value) {
						BasicLogger.writeLog(TAG, "Configuration Changed: " + key + " - "
								+ value);
						if (key.equals(ConfigurationConstants.conf_server_time_out_key)) {
							int seconds = SharedPreferenceUtil
									.getSharedPrefsValue(
											ConfigurationConstants.conf_server_time_out_key,
											30);
							int milliseconds = seconds * 1000;
							HttpParams params = reqFactory.getHttpClient()
									.getParams();
							reqFactory.setReadTimeout(milliseconds);
							HttpConnectionParams.setConnectionTimeout(params,
									milliseconds);
							HttpConnectionParams.setSoTimeout(params,
									milliseconds);
						}

					}
				});

	}

	public synchronized static RestServiceInvoker getInstance() {
		if (INSTANCE == null) {
			INSTANCE = new RestServiceInvoker();
		}
		return INSTANCE;
	}

	@Override
	public <Params, Result> Result invoke(ServiceEndPoint<Result> endPoint,
			Params request) throws Exception {
		if (endPoint.getMethod().equalsIgnoreCase("post")) {
			try {
				Result result = template.postForObject(
						endPoint.getServiceURL(), request,
						endPoint.getResultType());
				Log.i(TAG, "Result: " + result);
				return result;
			} catch (Exception e) {
				Log.e(TAG, "Invoke method exception: " + e.getMessage());
				throw e;
			}
		} else if (endPoint.getMethod().equalsIgnoreCase("get")) {
			try {
				Result result = template.getForObject(endPoint.getServiceURL(),
						endPoint.getResultType(), request);
				Log.i(TAG, "Result: " + result);
				return result;
			} catch (Exception e) {
				Log.e(TAG, "Invoke method exception: " + e.getMessage());
				throw e;
			}
		}
		// TODO: complete other methods else if(endPoint.)

		return null;
	}
}
